package com.bridgeintelligent.tag.webserver.security;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.bridgeintelligent.tag.webserver.security.SsoService.SsoLoginData;
import com.bridgeintelligent.tag.webserver.security.aes.AesUtils;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import static com.bridgeintelligent.tag.webserver.security.SsoConstants.SSO_AUTHORIZATION_URI;
import static com.bridgeintelligent.tag.webserver.security.SsoConstants.SSO_LOGIN_PATH;
import static com.bridgeintelligent.tag.webserver.security.SsoConstants.SSO_HOME_PATH;

@Slf4j
@RestController
@RequestMapping("/sso")
@AllArgsConstructor
public class SsoAuthenticationController {

    private SsoConfiguration conf;
    private SsoService service;
    private DefaultAuthenticationController controller;

    @RequestMapping("/authorize")
    public void authorize(HttpServletRequest request, HttpServletResponse response)
            throws URISyntaxException, IOException {
        URI uri = new URI(request.getRequestURL().toString());
        String redirectUrl = String.format(
            SSO_LOGIN_PATH,
            uri.getHost(),
            ( uri.getPort() == -1 ) ? 8089 : uri.getPort(),
            conf.getContextPath()
        );
        String addr = String.format(
                SSO_AUTHORIZATION_URI,
                conf.getDomain(),
                conf.getPort(),
                redirectUrl,
                conf.getClientId());
        log.info( "SSO调试-1: " + addr );
        response.sendRedirect(addr);
    }

    @RequestMapping("/login")
    public void login(String code, @RequestParam(required = false) String state,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.info( "SSO调试-2-1: code=" + code + ", state" + state );
        SsoLoginData user = service.syncUesrData(code, state);
        log.info( "SSO调试-2-6: code=" + code + ", state" + state );
        String username = AesUtils.aesEncrypt(user.getUsername(), AesUtils.AES_KEY);
        String password = AesUtils.aesEncrypt(SsoConstants.PASSWORD, AesUtils.AES_KEY);
        controller.login(username, password, response);
        writeTokenToCookie(user, response);
        redirectToHome(request, response);
    }

    @RequestMapping("/info")
    public LoginResponse.Data fetchUserInfo() {
        return new LoginResponse.Data(TagSecurityHelper.currentUser(), TagSecurityHelper.currentPermissions());
    }

    private void writeTokenToCookie(SsoLoginData user, HttpServletResponse response) {
        Cookie cookie;
        {
            cookie = new Cookie("sso_token", user.getToken());
            response.addCookie(cookie);
        }
        {
            cookie = new Cookie("sso_refresh_token", user.getToken());
            response.addCookie(cookie);
        }
        {
            cookie = new Cookie("sso_last_access", String.valueOf(System.currentTimeMillis()));
            response.addCookie(cookie);
        }
        {
            cookie = new Cookie("sso_token_expires", user.getExpires());
            response.addCookie(cookie);
        }
    }

    private void redirectToHome(HttpServletRequest request, HttpServletResponse response)
            throws IOException, URISyntaxException {
        URI uri = new URI(request.getRequestURL().toString());
        String addr = String.format(
                SSO_HOME_PATH,
                uri.getHost(),
                ( uri.getPort() == -1 ) ? 8089 : uri.getPort(),
                conf.getContextPath());
        response.sendRedirect(addr);
    }
}
